package com.cimr.comm.session;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.cimr.comm.cache.RedisDao;
import org.apache.shiro.session.Session;
import redis.clients.jedis.Jedis;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * Session 管理
 *
 */
@SuppressWarnings("unchecked")
public class ShiroSessionRepositoryRedis extends RedisDao implements ShiroSessionRepository {
    private static final Log log = LogFactory.get();
    public static final String REDIS_SHIRO_SESSION = "cimr-frame-shiro-session:";
    //这里有个小BUG，因为Redis使用序列化后，Key反序列化回来发现前面有一段乱码，解决的办法是存储缓存不序列化
    public static final String REDIS_SHIRO_ALL = "*cimr-frame-shiro-session:*";
    private static final int SESSION_VAL_TIME_SPAN = 18000;
    private static final int DB_INDEX = 1;

//    private RuntimeSchema<Session> schema = RuntimeSchema.createFrom(Session.class);

    public ShiroSessionRepositoryRedis(String host, int port, String clientName, String password) {
        super(host, port, clientName, password);
    }

    /**
     * 把session存入redis
     * @param session
     */
    public void saveSession(Session session) {
        if (session == null || session.getId() == null)
            throw new NullPointerException("session is empty");
        try {
            byte[] key = ObjectUtil.serialize(buildRedisSessionKey(session.getId()));

            //不存在才添加。
            if(null == session.getAttribute(CustomSessionManager.SESSION_STATUS)){
            	//Session 踢出自存存储。
            	SessionStatus sessionStatus = new SessionStatus();
            	session.setAttribute(CustomSessionManager.SESSION_STATUS, sessionStatus);
            }
            
            byte[] value = ObjectUtil.serialize(session);
            long sessionTimeOut = session.getTimeout() / 1000;
            Long expireTime = sessionTimeOut + SESSION_VAL_TIME_SPAN + (5 * 60);
            saveValueByKey(DB_INDEX, key, value, expireTime.intValue());
        } catch (Exception e) {
            log.error("save session error，id:{}", session.getId());
            log.error(e);
        }
    }

    public void deleteSession(Serializable id) {
        if (id == null) {
            throw new NullPointerException("session id is empty");
        }
        try {
            deleteByKey(DB_INDEX, ObjectUtil.serialize(buildRedisSessionKey(id)));
        } catch (Exception e) {
            log.error(e, "删除session出现异常，id:{}", id);
        }
    }

    public Session getSession(Serializable id) {
        if (id == null)
            throw new NullPointerException("session id is empty");
        Session session = null;
        try {
            byte[] value = getValueByKey(DB_INDEX, ObjectUtil.serialize(buildRedisSessionKey(id)));
            session = ObjectUtil.unserialize(value);
        } catch (Exception e) {
            log.error(e, "获取session异常，id:{}",id);
        }
        return session;
    }

    /**
     * 获取所有Session
     * @param dbIndex
     * @param redisShiroSession
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public Collection<Session> getAllSession(int dbIndex, String redisShiroSession) throws Exception {
        boolean isBroken = false;
        Set<Session> sessions = new HashSet<Session>();
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.select(dbIndex);

            Set<byte[]> byteKeys = jedis.keys((ShiroSessionRepositoryRedis.REDIS_SHIRO_ALL).getBytes());
            if (byteKeys != null && byteKeys.size() > 0) {
                for (byte[] bs : byteKeys) {
                    Session obj = ObjectUtil.unserialize(jedis.get(bs));
                    if(obj instanceof Session){
                        sessions.add(obj);
                    }
                }
            }
        } catch (Exception e) {
            isBroken = true;
            throw e;
        } finally {
            returnResource(jedis, isBroken);
        }
        return sessions;
    }

    public Collection<Session> getAllSessions() {
    	Collection<Session> sessions = null;
		try {
			sessions = getAllSession(DB_INDEX,REDIS_SHIRO_SESSION);
		} catch (Exception e) {
            log.error(e, "获取全部session 异常");
		}
       
        return sessions;
    }

    private String buildRedisSessionKey(Serializable sessionId) {
        return REDIS_SHIRO_SESSION + sessionId;
    }
}
